import os.path
import logging
from functools import partial

from PyQt5.QtWidgets import QPushButton, QMessageBox
import dbus
import json

from frw.vacwx import IVacWidget, UI_Mapping
from .pagevac_panel import PanelPageVac
from .pagevac_plc import PLC_PageVac
from .pagevac_udf import UDF_PageVac
from .pagevac_uiconf import UIConfPageVac  # i5os自定义的PLC.ui文件
from .pagevac_editor import EditorPageVac

from ioslave.slavelist import SlaveList

class I5osDBusListener:
    DBUS_INFO = {
        "Name"      : "com.app.i5os",
        "Path"      : "/app",
        "Interface" : "com.app.i5os.registry",
        "Signal"    : "switchapp"
    }

    def __init__(self, parent=None):
        if parent:
            self.parent = parent
        self.session_bus = dbus.SessionBus()

    def listen(self, callback):
        try:
            proxy = self.session_bus.get_object(self.DBUS_INFO["Name"],
                                                self.DBUS_INFO["Path"])
            proxy.connect_to_signal(self.DBUS_INFO["Signal"],
                                    callback,
                                    dbus_interface=self.DBUS_INFO["Interface"]
                                    # , arg0="123"  # String argument matching
                                    )
        except dbus.exceptions.DBusException as e:
            logging.error(e)


class MainWndVac(IVacWidget):
    Map_Slave2Vac = {
        "PANEL": PanelPageVac,
        "PLC32": PLC_PageVac,
        "PLC48": PLC_PageVac,
        "IAPEC": None,
    }

    def __init__(self, isEditMode=False):
        """ if isEditMode is not 'False', u would get a list of conf-files """
        super().__init__()

        # attributes
        self.page_editor_index = 0  # 用于记录编辑页面的page_index，用于切换sackedWidget时setCurrentIndex
        self.page_normal_start = self.page_editor_index + 1
        self.page_normal_default = 1  # 默认的normal模式显示页index

        self.create_pages()
        if isEditMode:
            list_io_files = isEditMode

            self.create_editor_btns(list_io_files)
            self.switch_to_editor_mode()
            self.switch_editor_data(list_io_files[0])

        self._active()

    def __del__(self):  # ??
        print("MainWndVac对象析构...")
        # dump database -->> config file.
        # self.switch_to_normal_mode()

    def _active(self):
        self.return_caller_btn.clicked.connect(self.return_to_dbus_caller)
        self.leave_editor_btn.clicked.connect(self.switch_to_normal_mode)
        self.dbus_active()

    def dbus_active(self):
        def dbus_switch_page(message):
            """ Message: {
                "from": "yaml",
                "open_file": [
                    "plc-cnc.ini.yaml"
                ],
                "page_to": "editor"
            }
            """
            logging.debug("Received signal (by connecting using remote object) and it says: " + message)
            QMessageBox.about(self, "警告", "response by PyQt5 signal listener: {}".format(message))
            dict_msg = json.loads(message)
            try:
                if dict_msg["appname"] != "IODebugging":  return
                if dict_msg["page_to"] == "editor":
                    self.switch_to_editor_mode()
                else:
                    raise Exception("Fail to parser the DBus-Message: [{}]".format(message))
            except:
                QMessageBox.about(self, "警告", "无法解析的DBus消息: {}".format(message))

        dbus = I5osDBusListener()
        dbus.listen(dbus_switch_page)

    def switch_page(self, page_index):
        self.page_stack_wx.setCurrentIndex(page_index)
        # # 若存在表格控件，则刷新表格数据
        # vac_in_stack = self.page_stack_wx.currentWidget()
        # if hasattr(vac_in_stack, "table_wx"):  # 非标查询，依赖table的对象名-->可以改为遍历
        #     table_page_stack = vac_in_stack.show_stack_wx
        #     subpage_index = table_page_stack.currentIndex()
        #     vac_in_stack.on_title_btn_clicked(subpage_index)  # 刷新数据

    def create_pages(self):
        Slave_LIST = SlaveList("./ioslave/libioslave.so")  # 板卡列表
        slave_address_from = 0

        # 首先创建Editor页面
        self.page_stack_wx.insertWidget(self.page_editor_index, EditorPageVac())

        index = [self.page_normal_start]  # 引用传递
        def create_page(list_index, title_btn_name, page_wx):  # 为使index改写，利用list包装int_index，实现引用传递
            index = list_index[0]

            page_btn = QPushButton(title_btn_name)
            page_btn.clicked.connect(partial(self.switch_page, index))
            self.page_stack_wx.insertWidget(index, page_wx)
            self.bar_btns_layout.addWidget(page_btn)
            list_index[0] += 1

        # 创建动态PageVac
        for tuple_slave_info in Slave_LIST.get_slave_list():
            # tuple_slave_info = ("SLAVE_NAME", SLAVE_LENGTH)
            slave_name = tuple_slave_info[0]
            slave_length = tuple_slave_info[1]

            page_class = self.Map_Slave2Vac[slave_name]
            if not page_class:
                continue
            page = page_class(address=(slave_address_from, slave_address_from + slave_length))
            create_page(index, slave_name, page)

            slave_address_from += slave_length  # 更新板卡地址记录

        # 静态PageVac
        # create_page(index, "PLC板卡", PLC_PageVac())  # just a test !!
        create_page(index, "自定义模式", UDF_PageVac())
        create_page(index, "PLC选项", UIConfPageVac())

        # 初始化首页【or 末页】
        # self.page_stack_wx.setCurrentIndex(self.page_normal_default) --> 如果采用这种格式，更节省资源，但依赖于ui文件stack对象当前的currentIndex
        self.switch_page(self.page_normal_default)

    def create_editor_btns(self, list_config_path):  # 该函数一般由dbus模块调用
        """ 根据配置文件的路径信息，生成Editor模式下的 btns on bar """
        for path_config in list_config_path:
            _, config_file_name = os.path.split(path_config)
            page_btn = QPushButton(config_file_name)
            page_btn.clicked.connect(partial(self.switch_editor_data, path_config))  # 不再是切换页面，而是在当前页面更换数据
            self.bar_editor_layout.addWidget(page_btn)

    def switch_editor_data(self, path_config):
        # 刷新ui-table（一般已经切换至Editor-Mode）
        editor_page_vac = self.page_stack_wx.currentWidget()
        editor_page_vac.import_config(path_config)

    def switch_to_editor_mode(self):
        self.page_stack_wx.setCurrentIndex(self.page_editor_index)
        if self.bottom_stack_wx.currentIndex() != 1:
            self.bottom_stack_wx.setCurrentIndex(1)  # 切换btn-bar至editor模式

    def switch_to_normal_mode(self):
        """ 一般用于从“编辑模式”切换回功能页面 """
        if self.bottom_stack_wx.currentIndex() != 0:
            self.bottom_stack_wx.setCurrentIndex(0)  # 切换到正常的btn-bar
            self.switch_page(self.page_normal_default)  # 默认跳转到首页

    def return_to_dbus_caller(self):  # ??
        self.switch_to_normal_mode()
        # dbus call the caller...
